import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const fs = require('fs');
const path = require('path');
const axios = require('axios');
const template = require('art-template');
import { dirname } from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
let typesMap = new Map();
let apiMaps = new Map();
const getKebabCase = (str) => {
  let temp = str.replace(/[A-Z]/g, function (i) {
    return '_' + i.toLowerCase();
  });
  if (temp.slice(0, 1) === '_') {
    temp = temp.slice(1); //如果首字母是大写，执行replace时会多一个_，需要去掉
  }
  return temp;
};

const getApiData = async () => {
  const res = await axios.get('http://localhost:8080/v3/api-docs');
  if (res.status !== 200) {
    throw new Error('后台接口服务连接失败');
  }
  return res.data;
};
const getFieldType = (type) => {
  switch (type) {
    case 'string':
      return 'string';
    case 'integer':
      return 'number';
  }
  return '';
};
const typeField = (propertiesKey, propertiesObj) => {
  return {
    name: propertiesKey,
    description: propertiesObj.description || '注释',
    type: getFieldType(propertiesObj.type),
    path: '',
    required: false
  };
};

const analysisType = (typeObj, name) => {
  const title = typeObj.title || '';
  const required = typeObj.required || [];
  const properties = typeObj.properties || {};
  const fields = [];
  for (const propertiesKey in properties) {
    const propertiesObj = properties[propertiesKey];
    const field = typeField(propertiesKey, propertiesObj);
    if (required.includes(propertiesKey)) {
      field.required = true;
    }
    fields.push(field);
  }
  return {
    name,
    description: title || '注释',
    fields
  };
};
const analysisTypes = (schemas) => {
  if (!schemas || schemas.length == 0) {
    return;
  }
  for (const schema in schemas) {
    const typeObj = schemas[schema];
    typesMap.set(schema, analysisType(typeObj, schema));
  }
};
const analysisTags = (tags) => {
  let list = [];
  for (const tag of tags) {
    const tagName = tag.name.replace('Controller', '');
    list.push({
      tagName,
      name: tag.name,
      description: tag.description
    });
  }
  return list;
};
/**
 * 解析Post请求参数
 * @param requestBody
 * @returns {string}
 */
const analysisRequestBody = (requestBody) => {
  if (!requestBody) {
    return;
  }
  const requestObjStr = requestBody.content['application/json'].schema.$ref;
  const requestStr = requestObjStr.replace('#/components/schemas/', '');
  return requestStr;
};
/**
 * 解析返回值
 * @param value
 * @param method
 * @param path
 */
const analysisResponseBody = (responses) => {
  if (!responses) {
    return;
  }
  if (!responses['200']['content']) {
    return 'void';
  }
  let type = responses['200']['content']['*/*']['schema']['type'];
  if (type) {
    return getFieldType(type);
  }
  type = responses['200']['content']['*/*']['schema']['$ref'].replace('#/components/schemas/R', '');
  return type == '' ? 'void' : type;
};

const apiPathPackage = (value, method, path) => {
  if (!value) {
    return;
  }
  const key = value.tags[0];
  let apiList = apiMaps.get(key);
  if (!apiList) {
    apiList = [];
  }
  const params = analysisRequestBody(value.requestBody);
  const response = analysisResponseBody(value.responses);
  apiList.push({
    apiName: value.operationId,
    method: method,
    path,
    modules: path.split('/')[1],
    description: value.summary || '接口注释',
    params: params,
    response: response || 'any'
  });
  apiMaps.set(key, apiList);
};
const analysisApiPath = (paths) => {
  if (!paths || paths.length == 0) {
    return;
  }
  for (let path in paths) {
    const pathObj = paths[path];
    apiPathPackage(pathObj['get'], 'MethodEnum.GET', path);
    apiPathPackage(pathObj['post'], 'MethodEnum.POST', path);
    apiPathPackage(pathObj['delete'], 'MethodEnum.DELETE', path);
    apiPathPackage(pathObj['put'], 'MethodEnum.PUT', path);
  }
};

const apiData = await getApiData();
const tags = apiData.tags;
if (!tags || tags.length == 0) {
  console.info('接口生成完成,接口文件: 0');
}
const apiTypesBuild = (apis, path) => {
  const apiTypes = [];
  const types = new Map();
  for (const api of apis) {
    if (api.params && api.params != 'any') {
      const type = typesMap.get(api.params);
      if (!type.path) {
        apiTypes.push(type);
        const typePath = `/@/api/${path}/types`;
        type.path = typePath;
      }
      const list = types.get(type.path) || [];
      list.push(api.params);
      types.set(type.path, list);
    }
    if (api.response && api.response != 'any' && api.response != 'void') {
      const type = typesMap.get(api.response);
      if (!type.path) {
        apiTypes.push(type);
        const typePath = `/@/api/${path}/types`;
        type.path = typePath;
      }
      const list = types.get(type.path) || [];
      list.push(api.response);
      types.set(type.path, list);
    }
  }
  return {
    apiTypes,
    types
  };
};
const createFile = (path, data) => {
  fs.writeFile(path, data, (error) => {
    // 创建失败
    if (error) {
      console.log(`创建失败：${error}`);
    }
  });
};
analysisTypes(apiData.components.schemas);
analysisApiPath(apiData.paths);
const fileList = analysisTags(tags);
function mkdirsSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    if (mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
}
const apiTypesImport = (map) => {
  const obj = {};
  map.forEach((value, key) => {
    obj[key] = value.join(', ');
  });
  return obj;
};
for (const fileObj of fileList) {
  const dirName = getKebabCase(fileObj.tagName);
  const apis = apiMaps.get(fileObj.name);
  if (!apis || apis.length == 0) {
    continue;
  }
  fileObj.apiList = apis;
  const path = `src/api/${apis[0].modules}/${dirName}`;
  mkdirsSync(path, { recursive: true });
  //创建api类型的ts文件
  const { apiTypes, types } = apiTypesBuild(apis, `${apis[0].modules}/${dirName}`);
  let data = template(__dirname + '/type.art', { types: apiTypes });

  createFile(path + '/types.ts', data);
  fileObj.types = apiTypesImport(types);
  //创建api的ts文件
  data = template(__dirname + '/api.art', fileObj);
  createFile(path + '/index.ts', data);
}
console.info('接口生成完成,接口文件: ' + tags.length + '个');
